package com.example.sknetwork

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.InstanceCreator
import com.google.gson.internal.bind.TypeAdapters
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory
import com.google.gson.internal.ConstructorConstructor
import com.google.gson.FieldNamingPolicy
import com.google.gson.internal.Excluder
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory
import com.google.gson.internal.bind.CollectionTypeAdapterFactory
import java.lang.Exception
import java.lang.reflect.Field
import java.lang.reflect.Type

/**
 * 解决gson解析类型不对 数据crash
 * Created by huilin on 2017/8/23.
 * 参考博客：https://blog.csdn.net/a850125665/article/details/79214797
 * 使用方法
 * 1）MGson.getInstance()得到Gson对象
 * 2)然后使用相对应的gson方法即可
 * 解决:
 * 1)要{}后端给[]返回实例对象
 * 2)要[]后端给{}返回空数组
 * 3)要int.class, Integer.class,short.class, Short.class,long.class, Long.class,double.class, Double.class,
 * float.class, Float.class后端给的非数字类型返回0
 * 4)要String后端给了[],{}等类型返回""
 *
 * @author add by ssq
 */
object MGson {
    val instance: Gson
        get() = HolderClass.instance

    /**
     * 生成注册自定义的对象处理器与集合处理器的Gson，方法
     *
     */
    private fun newGson(): Gson {
        val gsonBuilder = GsonBuilder()
        val builder = gsonBuilder.javaClass as Class<*>
        var f: Field? = null
        try {
            //通过反射得到构造器
            f = builder.getDeclaredField("instanceCreators")
            f.isAccessible = true
            //得到此属性的值
            val `val` = f[gsonBuilder] as Map<Type, InstanceCreator<*>>
            //注册String类型处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    String::class.java,
                    GsonTools.stringTypeAdapter()
                )
            )
            //注册int.class, Integer.class处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    Int::class.javaPrimitiveType,
                    Int::class.java,
                    GsonTools.longAdapter(0)
                )
            )
            //注册short.class, Short.class处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    Short::class.javaPrimitiveType,
                    Short::class.java,
                    GsonTools.longAdapter(1)
                )
            )
            //注册long.class, Long.class处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    Long::class.javaPrimitiveType,
                    Long::class.java,
                    GsonTools.longAdapter(2)
                )
            )
            //注册double.class, Double.class处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    Double::class.javaPrimitiveType,
                    Double::class.java,
                    GsonTools.longAdapter(3)
                )
            )
            //注册float.class, Float.class处理器
            gsonBuilder.registerTypeAdapterFactory(
                TypeAdapters.newFactory(
                    Float::class.javaPrimitiveType,
                    Float::class.java,
                    GsonTools.longAdapter(4)
                )
            )
            //注册反射对象的处理器
            gsonBuilder.registerTypeAdapterFactory(
                ReflectiveTypeAdapterFactory(
                    ConstructorConstructor(`val`),
                    FieldNamingPolicy.IDENTITY,
                    Excluder.DEFAULT,
                    JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor(`val`))
                )
            )
            //注册集合的处理器
            gsonBuilder.registerTypeAdapterFactory(
                CollectionTypeAdapterFactory(
                    ConstructorConstructor(`val`)
                )
            )
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return gsonBuilder.create()
    }

    private object HolderClass {
        val instance = newGson()
    }
}